import { defineComponent, inject, toRef, provide, createVNode, Fragment } from 'vue';
import { deepCopy } from '../use/deepClone.js';

const FormContextKey = Symbol('FormContextKey');
const index = /* @__PURE__ */ defineComponent({
  name: 'Form',
  props: {
    labelWidth: {
      type: Number
    },
    inline: {
      type: Boolean
    },
    model: {
      type: Object
    },
    autocomplete: {
      type: String
    },
    validation: {
      type: Object
    },
    errorTransfer: {
      type: Boolean,
      default: false
    },
    errorAlign: {
      type: String,
      default: 'right'
    },
    onBeforeSubmit: {
      type: Function
    },
    rules: {
      type: Object
    }
  },
  emits: ['change', 'beforeSubmit'],
  setup(props, {
    emit,
    slots,
    expose
  }) {
    const formCtx = inject(FormContextKey, null);
    if (formCtx) {
      console.warn('Form can not be nested');
    }
    const initModel = deepCopy(props.model);
    const _onChange = (name, v) => {
      // props.model[name] = v;
      emit('change', name, v);
      // 触发验证
      const check = checks.get(name);
      check && check(v);
    };
    const checks = new Map();
    const clears = new Map();
    const setCheck = (name, checkFn) => {
      checks.set(name, checkFn);
    };
    const setClearValid = (name, checkFn) => {
      clears.set(name, checkFn);
    };
    const ctx = {
      labelWidth: toRef(props.labelWidth),
      inline: props.inline,
      model: props.model,
      validation: props.validation,
      errorTransfer: props.errorTransfer,
      errorAlign: props.errorAlign,
      onChange: _onChange,
      setCheck,
      setClearValid,
      rules: toRef(props.rules)
    };
    provide(FormContextKey, ctx);

    /**
     * 获取值
     * @param obj
     * @param fields name值或数组
     * @returns
     */
    const _getValueByPath = (obj, fields) => {
      if (fields.includes(".")) {
        const fieldsArr = fields.split(".");
        return fieldsArr.reduce((pre, cur) => {
          return pre[cur];
        }, obj);
      }
      return obj[fields];
    };

    /**
     * 根据路径获取值
     * @param fields name值或数组
     * @returns
     */
    const getValueByPath = fields => {
      return _getValueByPath(props.model, fields);
    };
    const onSubmit = e => {
      e.preventDefault();
      if (props.onBeforeSubmit) {
        return props.onBeforeSubmit();
      }
      return false;
    };
    const validate = async () => {
      let valid = true;
      for (const [name, checkFn] of checks) {
        const val = getValueByPath(name);
        if (!(await checkFn(val))) {
          valid = false;
        }
      }
      return valid;
    };
    const clearValidate = () => {
      for (const [name, clearFn] of clears) {
        clearFn();
      }
    };
    expose({
      validate,
      clearValidate,
      resetFields() {
        const initData = deepCopy(initModel);
        Object.assign(props.model, initData);
      },
      validateFields(names) {
        names.forEach(name => {
          const check = checks.get(name);
          check && check(props.model[name]);
        });
      }
    });
    return () => createVNode(Fragment, null, [createVNode("form", {
      "class": {
        'cm-form': true,
        'cm-form-inline': props.inline
      },
      "onSubmit": onSubmit,
      "autocomplete": props.autocomplete
    }, [createVNode("button", {
      "type": "submit",
      "style": {
        display: 'none'
      }
    }, null), slots.default?.()])]);
  }
});

export { FormContextKey, index as default };
